﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Text;
using System.Reflection;
using System.ComponentModel;

namespace NETCommon.Data
{
    public static class NExtenders
    {
        public static UInt64 Convert<T>(T val)
        {
            byte[] src = BitConverter<T>.GetBytes(val);
            byte[] dest = new byte[8];
            Buffer.BlockCopy(src, 0, dest, 0, src.Length);

            return BitConverter.ToUInt64(dest, 0);
        }
        /// <summary>
        /// NETCommon Extender: Clone a Generic IEnumerable
        /// </summary>
        public static IEnumerable<T> Clone<T>(this IEnumerable<T> collection)
        {
            using (var stream = new System.IO.MemoryStream())
            {
                var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                binaryFormatter.Serialize(stream, collection); //serialize to stream
                stream.Position = 0;
                //deserialize from stream.
                return binaryFormatter.Deserialize(stream) as IEnumerable<T>;
            }
        }
        /// <summary>
        /// NETCommon Extender: Convert to DataTable from a Generic IEnumerable 
        /// </summary>
        public static DataTable ToDatatable<T>(this IEnumerable<T> array)
        {
            try
            {
                if (!array.IsUnique())
                {
                    return null;
                }

                PropertyInfo[] properties = array.First().GetType().GetProperties();
                DataTable dt = CreateDataTable(properties);

                foreach (T o in array)
                    FillData<T>(properties, dt, o);

                return dt;
            }
            catch (Exception e)
            {
                return null;
            }
        }
        public static T ToItem<T>(this DataRow row)
        {
            T obj = default(T);
            if (row != null)
            {
                obj = Activator.CreateInstance<T>();

                foreach (DataColumn column in row.Table.Columns)
                {
                    PropertyInfo prop = obj.GetType().GetProperty(column.ColumnName);
                    try
                    {
                        object value = row[column.ColumnName];
                        prop.SetValue(obj, value, null);
                    }
                    catch
                    {
                        // You can log something here
                        throw;
                    }
                }
            }

            return obj;
        }
        public static IList<T> ToList<T>(this IList<DataRow> rows)
        {
            IList<T> list = null;

            if (rows != null)
            {
                list = new List<T>();

                foreach (DataRow row in rows)
                {
                    T item = ToItem<T>(row);
                    list.Add(item);
                }
            }

            return list;
        }
        public static IList<T> ToList<T>(this DataTable table)
        {
            if (table == null)
            {
                return null;
            }

            List<DataRow> rows = new List<DataRow>();

            foreach (DataRow row in table.Rows)
            {
                rows.Add(row);
            }

            return ToList<T>(rows);
        }

        #region ObjectArray to Datatable
        private static bool IsUnique<T>(this IEnumerable<T> data)
        {
            bool ret = false;

            if (data == null || data.Count<T>() == 0)
            {
                return ret;
            }

            try
            {
                IEnumerator<T> iterator = data.GetEnumerator();

                Type myType = null;
                if (iterator.MoveNext())
                {
                    myType = iterator.Current.GetType();
                }
                while (iterator.MoveNext())
                {

                    Type myCurerntType = iterator.Current.GetType();
                    if (myType != myCurerntType)
                    {
                        return ret;
                    }
                }

                ret = true;
            }
            catch (System.Exception ex)
            {
                ret = false;
            }

            return ret;
        }
        private static DataTable CreateDataTable(PropertyInfo[] properties)
        {
            DataTable dt = new DataTable();
            DataColumn dc = null;
            foreach (PropertyInfo pi in properties)
            {
                dc = new DataColumn { ColumnName = pi.Name, DataType = pi.PropertyType };
                dt.Columns.Add(dc);
            }
            return dt;
        }
        private static void FillData<T>(PropertyInfo[] properties, DataTable dt, T o)
        {
            DataRow dr = dt.NewRow();
            foreach (PropertyInfo pi in properties)
            {
                dr[pi.Name] = pi.GetValue(o, null);
            }
            dt.Rows.Add(dr);
        }
        #endregion

    }
    public class BitConverter<T>
    {
        public static readonly Func<T, byte[]> GetBytes = x => new byte[] { };

        static BitConverter()
        {
            BitConverter<byte>.GetBytes = x => new byte[] { x };
            BitConverter<bool>.GetBytes = x => BitConverter.GetBytes(x);
            BitConverter<char>.GetBytes = x => BitConverter.GetBytes(x);
            BitConverter<double>.GetBytes = x => BitConverter.GetBytes(x);
            BitConverter<Int16>.GetBytes = x => BitConverter.GetBytes(x);
            BitConverter<Int32>.GetBytes = x => BitConverter.GetBytes(x);
            BitConverter<Int64>.GetBytes = x => BitConverter.GetBytes(x);
            BitConverter<Single>.GetBytes = x => BitConverter.GetBytes(x);
            BitConverter<UInt16>.GetBytes = x => BitConverter.GetBytes(x);
            BitConverter<UInt32>.GetBytes = x => BitConverter.GetBytes(x);
            BitConverter<UInt64>.GetBytes = x => BitConverter.GetBytes(x);
        }
    }
}
